package com.ruoyi.common.core.utils;

import com.ruoyi.common.core.constant.StrConst;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;

/**
 * 实体类名称: DecimalUtils<br/>
 * 描述: 小数decimal相关工具类<br/>
 * 创建人: caoyu<br/>
 * 创建时间: 2021/10/9 23:58
 */
//@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
@SuppressWarnings("all")
public class DecimalUtils {

	public static final BigDecimal ZERO = BigDecimal.ZERO;

	public static final BigDecimal ONE_HUNDRED = new BigDecimal("100");

	private DecimalUtils() {
	}

	/**
	 * 方法名: isEmpty
	 * 方法描述: 判断是否为空<br/>
	 * 参数: <br/>
	 * 返回类型: java.lang.Boolean<br/>
	 * 创建者: Cao.Yu<br/>
	 * 创建时间: 14:40 2021/8/7
	 */
	public static Boolean isEmpty(BigDecimal x) {
		return null == x || ZERO.compareTo(x) == 0;
	}

	/**
	 * 方法名: isAllEmpty <br/>
	 * 描述: 全为 null 或 0 <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/3/30 11:33 上午
	 */
	public static Boolean isAllEmpty(BigDecimal... ns) {
		if (ArrayUtils.isEmpty(ns)) {
			return true;
		}else {
			for (BigDecimal bd : ns) {
				if (isNotEmpty(bd)) {
					return false;
				}
			}
			return true;
		}
	}

	/**
	 * 方法名: isAnyEmpty <br/>
	 * 描述: 任何一个为 null 或 0  <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/3/30 11:40 上午
	 */
	public static Boolean isAnyEmpty(BigDecimal... ns) {
		if (ArrayUtils.isEmpty(ns)) {
			return true;
		}else {
			for (BigDecimal bd : ns) {
				if (isEmpty(bd)) {
					return true;
				}
			}
			return false;
		}
	}

	/**
	 * 方法名: isNotEmpty
	 * 方法描述: 判断非空<br/>
	 * 参数: <br/>
	 * 返回类型: java.lang.Boolean<br/>
	 * 创建者: Cao.Yu<br/>
	 * 创建时间: 14:40 2021/8/7
	 */
	public static Boolean isNotEmpty(BigDecimal x) {
		return !isEmpty(x);
	}

	/**
	 * 方法名: greaterThan
	 * 方法描述: 判断第一个参数x是否大于第二个参数y<br/>
	 * 参数: <br/>
	 * 返回类型: java.lang.Boolean<br/>
	 * 创建者: Cao.Yu<br/>
	 * 创建时间: 11:03 2021/8/8
	 */
	public static Boolean greaterThan(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.compareTo(y) > 0;
	}

	public static int compareTo(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.compareTo(y);
	}

	/**
	 * 方法名: equals
	 * 方法描述: 判断第一个参数x是否等于第二个参数y<br/>
	 * 参数: <br/>
	 * 返回类型: java.lang.Boolean<br/>
	 * 创建者: Cao.Yu<br/>
	 * 创建时间: 11:03 2021/8/8
	 */
	public static Boolean equals(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.compareTo(y) == 0;
	}

	/**
	 * @方法名：equalsZero
	 * @描述： 判断参数x是否等于0
	 * @作者： Kuang.JiaZhuo
	 * @日期： Created in 2022/5/16 16:08
	 */
	public static Boolean equalsZero(BigDecimal x){
		return equals(x, ZERO);
	}

	/**
	 * 方法名: notEqualsZero <br/>
	 * 描述: 不等于0 <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/3/29 11:31 上午
	 */
	public static Boolean notEqualsZero(BigDecimal x){
		return !equalsZero(x);
	}

	public static Boolean notEquals(BigDecimal x, BigDecimal y){
		return !equals(x, y);
	}

	/**
	 * @Method equalsHandred <br/>
	 * @Description 是否等于100 <br/>
	 * @Param x <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2023/4/7 14:57 <br/>
	 * @Return java.lang.Boolean
	 */
	public static Boolean equalsHandred (BigDecimal x) {
		return equals(x, ONE_HUNDRED);
	}

	/**
	 * @Method notEqualsHandred <br/>
	 * @Description 不等于100 <br/>
	 * @Param x <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2023/4/7 14:57 <br/>
	 * @Return java.lang.Boolean
	 */
	public static Boolean notEqualsHandred (BigDecimal x) {
		return !equalsHandred(x);
	}

	/**
	 * 方法名: greaterThanOrEquals
	 * 方法描述: 判断第一个参数x是否大于或等于第二个参数y<br/>
	 * 参数: <br/>
	 * 返回类型: java.lang.Boolean<br/>
	 * 创建者: Cao.Yu<br/>
	 * 创建时间: 11:03 2021/8/8
	 */
	public static Boolean greaterThanOrEquals(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.compareTo(y) > -1;
	}

	/**
	 * 方法名: greaterThanEqualsZero <br/>
	 * 描述: 大于等于0 <br/>
	 * 作者: Cao.Yu <br/>
	 * 日期: Created in 2022/5/7 18:02
	 */
	public static Boolean greaterThanEqualsZero(BigDecimal x) {
		return greaterThanOrEquals(x, ZERO);
	}

	/**
	 * 方法名: greaterThanZero <br/>
	 * 描述: 大于0 <br/>
	 * 作者: Cao.Yu <br/>
	 * 日期: Created in 2022/5/7 17:22
	 */
	public static Boolean greaterThanZero(BigDecimal x) {
		return greaterThan(x, ZERO);
	}

	/**
	 * 方法名: lessThan
	 * 方法描述: 判断第一个参数x是否小于第二个参数y<br/>
	 * 参数: <br/>
	 * 返回类型: java.lang.Boolean<br/>
	 * 创建者: Cao.Yu<br/>
	 * 创建时间: 11:03 2021/8/8
	 */
	public static Boolean lessThan(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.compareTo(y) < 0;
	}

	/**
	 * @方法名：lessThanZero
	 * @描述： 判断传入的参数是否小于0
	 * @作者： Kuang.JiaZhuo
	 * @日期： Created in 2022/5/5 11:04
	 */
	public static Boolean lessThanZero(BigDecimal x) {
		return lessThan(x, ZERO);
	}

	/**
	 * 方法名: lessThan
	 * 方法描述: 判断第一个参数x是否小于或等于第二个参数y<br/>
	 * 参数: <br/>
	 * 返回类型: java.lang.Boolean<br/>
	 * 创建者: Cao.Yu<br/>
	 * 创建时间: 11:03 2021/8/8
	 */
	public static Boolean lessThanOrEquals(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.compareTo(y) < 1;
	}

	/**
	 * @方法名：lessThanOrEqualsZero
	 * @描述： 判断所传入的值是否 <= 0
	 * @作者： Kuang.JiaZhuo
	 * @日期： Created in 2022/5/2 15:21
	 */
	public static Boolean lessThanOrEqualsZero(BigDecimal x){
		return lessThanOrEquals(x,ZERO);
	}

	/**
	 * 加法计算（result = x + y）
	 *
	 * @param x 被加数（可为null）
	 * @param y 加数 （可为null）
	 * @return 和 （可为null）
	 * @author Cao.Yu on 2020-03-30 14:52
	 */
	public static BigDecimal add(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.add(y);
	}

	/**
	 * 方法名: add <br/>
	 * 描述: 多参数连续相加 <br/>
	 * 		如果有参数为空 默认为0
	 * 作者: LeiYang <br/>
	 * 时间: Created in 2022/4/11 11:25
	 */
	public static BigDecimal add(final BigDecimal... decimals) {
		BigDecimal x = ZERO;
		if (ArrayUtils.isEmpty(decimals)) {
			return x;
		}
		for (BigDecimal decimal : decimals) {
			decimal = ObjectUtils.isEmpty(decimal) ? ZERO : decimal;
			x = add(x, decimal);
		}
		return x;
	}

	/**
	 * 减法计算(result = x - y)
	 *
	 * @param x 被减数（可为null）
	 * @param y 减数（可为null）
	 * @return BigDecimal 差 （可为null）
	 * @author Cao.Yu on 2020-03-30 14:47
	 */
	public static BigDecimal subtract(BigDecimal x, BigDecimal y) {
		if (isEmpty(x)) {
			x = ZERO;
		}
		if (isEmpty(y)) {
			y = ZERO;
		}
		return x.subtract(y);
	}

	/**
	 * @Method subtract <br/>
	 * @Description 连减 <br/>
	 * @Param decimals <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2022/8/16 16:26 <br/>
	 * @Return java.math.BigDecimal
	 */
	public static BigDecimal subtract(final BigDecimal... decimals) {
		BigDecimal x = BigDecimal.ZERO;
		if (ArrayUtils.isEmpty(decimals)) {
			return x;
		}
		int index = 1;
		for (BigDecimal decimal : decimals) {
			decimal = ObjectUtils.isEmpty(decimal) ? BigDecimal.ZERO : decimal;
			if (index == 1) {
				x = decimal;
			} else {
				x = DecimalUtils.subtract(x, decimal);
			}
			index++;
		}
		return x;
	}

	/**
	 * 乘法计算(result = x × y)
	 *
	 * @param x 乘数(可为null)
	 * @param y 乘数(可为null)
	 * @return BigDecimal 积
	 * @author Cao.Yu on 2020-03-30 14:14
	 */
	public static BigDecimal multiply(BigDecimal x, BigDecimal y) {
		if (isEmpty(x) || isEmpty(y)) {
			return ZERO;
		}
		return x.multiply(y);
	}

	/**
	 * 方法名: multiply <br/>
	 * 描述: 多参数连续相乘 <br/>
	 * 		只有有一个参数为null或0  结果都为0
	 * 作者: LeiYang <br/>
	 * 时间: Created in 2022/4/11 11:39
	 */
	public static BigDecimal multiply(final BigDecimal... decimals) {
		BigDecimal res = ZERO;
		if (ArrayUtils.isEmpty(decimals)) {
			return res;
		}
		for (int i = 0; i < decimals.length; i++) {
			if (isEmpty(decimals[i])) {
				return ZERO;
			}
			if (i == 0) {
				res = decimals[i];
			} else {
				res = multiply(res, decimals[i]);
			}
		}
		return res;
	}

	/**
	 * 除法计算(result = x ÷ y)  可以指定保留方式，比如四舍五入等(默认向上保留)
	 *
	 * @param x 被除数（可为null）
	 * @param y 除数（可为null）
	 * @return 商 （可为null）
	 * @author Cao.Yu on 2020-03-30 14:15
	 */
	public static BigDecimal divide(BigDecimal x, BigDecimal y) {
		return divide(x, y, 8, BigDecimal.ROUND_UP);
	}

	/**
	 * @Method divide <br/>
	 * @Description 除法计算(result = x ÷ y) <br/>
	 * @Param x 被除数
	 * @Param y 除数
	 * @Param roundingMode 可以不传，保留方式(默认向上保留) <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2022/9/19 14:57 <br/>
	 * @Return java.math.BigDecimal
	 */
	public static BigDecimal divide(BigDecimal x, BigDecimal y, int scale, int roundingMode) {
		if (isEmpty(x) || isEmpty(y)) {
			return ZERO;
		}
		if (Objects.equals(x, ZERO) || Objects.equals(y, ZERO)) {
			return ZERO;
		}
		// 结果为0.000..时，不用科学计数法展示
		return stripTrailingZeros(x.divide(y, scale, roundingMode));
	}

	/**
	 * 转为字符串(防止返回可续计数法表达式)
	 *
	 * @param x 要转字符串的小数
	 * @return String
	 * @author Cao.Yu on 2020-03-30 15:08
	 */
	public static String toPlainString(BigDecimal x) {
		if (isEmpty(x)) {
			return StrConst.STR_CONST_0;
		}
		return x.toPlainString();
	}

	/**
	 * 保留小数位数
	 *
	 * @param x     目标小数
	 * @param scale 要保留小数位数
	 * @return BigDecimal 结果向上保留
	 * @author Cao.Yu on 2020-03-30 15:17
	 */
	public static BigDecimal setScale(BigDecimal x, int scale) {
		if (isEmpty(x)) {
			return ZERO;
		}
		return x.setScale(scale, RoundingMode.UP);
	}

	/**
	 * 整型转为BigDecimal
	 *
	 * @param x(可为null)
	 * @return BigDecimal (可为null)
	 * @author Cao.Yu on 2020-03-30 22:24
	 */
	public static BigDecimal toBigDecimal(Integer x) {
		if (x == null) {
			return ZERO;
		}
		return new BigDecimal(x.toString());
	}

	/**
	 * 长整型转为BigDecimal
	 *
	 * @param x(可为null)
	 * @return BigDecimal (可为null)
	 * @author Cao.Yu on 2020-03-30 22:24
	 */
	public static BigDecimal toBigDecimal(Long x) {
		if (x == null) {
			return ZERO;
		}
		return new BigDecimal(x.toString());
	}

	/**
	 * 双精度型转为BigDecimal
	 *
	 * @param x(可为null)
	 * @return BigDecimal (可为null)
	 * @author Cao.Yu on 2020-03-30 22:24
	 */
	public static BigDecimal toBigDecimal(Double x) {
		if (x == null) {
			return ZERO;
		}
		return new BigDecimal(x.toString());
	}

	/**
	 * 单精度型转为BigDecimal
	 *
	 * @param x(可为null)
	 * @return BigDecimal (可为null)
	 * @author Cao.Yu on 2020-03-30 22:24
	 */
	public static BigDecimal toBigDecimal(Float x) {
		if (x == null) {
			return ZERO;
		}
		return new BigDecimal(x.toString());
	}

	/**
	 * 字符串型转为BigDecimal
	 *
	 * @param x(可为null)
	 * @return BigDecimal (可为null)
	 * @author Cao.Yu on 2020-03-30 22:24
	 */
	public static BigDecimal toBigDecimal(String x) {
		if (StringUtils.isEmpty(x)) {
			return ZERO;
		}
		return new BigDecimal(x);
	}

	/**
	 * 对象类型转为BigDecimal
	 *
	 * @param x(可为null)
	 * @return BigDecimal (可为null)
	 * @author Cao.Yu on 2020-03-30 22:24
	 */
	public static BigDecimal toBigDecimal(Object x) {
		if (x == null) {
			return ZERO;
		}
		BigDecimal result = null;
		try {
			result = toBigDecimal(x.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 方法名: zeroToNull <br/>
	 * 描述: 0 --> null <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/5/16 4:19 下午
	 */
	public static BigDecimal zeroToNull(BigDecimal n) {
		return null == n || ZERO.compareTo(n) == 0 ? null : n;
	}

	/**
	 * 倍数计算，用于单位换算
	 *
	 * @param x        目标数(可为null)
	 * @param multiple 倍数 (可为null)
	 * @return BigDecimal (可为null)
	 * @author Cao.Yu on 2020-03-30 22:43
	 */
	public static BigDecimal multiple(BigDecimal x, Integer multiple) {
		if (x == null || multiple == null) {
			return null;
		}
		return DecimalUtils.multiply(x, toBigDecimal(multiple));
	}

	public static BigDecimal multiple(BigDecimal x, BigDecimal multiple) {
		if (x == null || multiple == null) {
			return null;
		}
		return DecimalUtils.multiply(x, toBigDecimal(multiple));
	}

	/**
	 * 去除小数点后的0（如: 输入1.000返回1）
	 *
	 * @param x 目标数(可为null)
	 */
	public static BigDecimal stripTrailingZeros(BigDecimal x) {
		if (x == null) {
			return ZERO;
		}
		return x.stripTrailingZeros();
	}

	/**
	 * BigDecimal转换为Integer
	 *
	 * @param x 目标数(可为null)
	 * @return Integer
	 */
	public static Integer bigToInt(BigDecimal x) {
		if (x == null) {
			return 0;
		}
		int i = x.toString().indexOf(".");
		if (i < 0) {
			return Integer.parseInt(x.toString());
		}
		return Integer.parseInt(x.toString().substring(0, i));
	}

	/**
	 * 方法名：roundUp<br/>
	 * 描述： 向上取整，不管保留数字后面是大是小(0除外)都会进1<br/>
	 * 作者： Cao.Yu<br/>
	 * 日期： Created in 2021-10-19 16:29<br/>
	 */
	public static BigDecimal roundUp(BigDecimal num) {
		if (num == null) {
			return ZERO;
		}
		return num.setScale(0, RoundingMode.UP);
	}

	/**
	 * @Method isDecimal <br/>
	 * @Description 是否是小数 <br/>
	 * @Param a <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2022/8/2 11:29 <br/>
	 * @Return boolean
	 */
	public static boolean isDecimal(BigDecimal a) {
		if (a == null) {
			return false;
		}
		return !(new BigDecimal(a.intValue()).compareTo(a)==0);
	}

	/**
	 * @Method isInteger <br/>
	 * @Description 是否是整数 <br/>
	 * @Param a <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2022/8/2 11:29 <br/>
	 * @Return boolean
	 */
	public static boolean isInteger(BigDecimal a) {
		if (a == null) {
			return false;
		}
		return new BigDecimal(a.intValue()).compareTo(a)==0;
	}

	/**
	 * 方法名: isAllPositive <br/>
	 * 描述: 均是正数 <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/3/17 12:43 下午
	 */
	public static boolean isAllPositive(BigDecimal... bds) {
		if (ArrayUtils.isEmpty(bds)) {
			return true;
		} else {
			for (BigDecimal bd : bds) {
				if (lessThanOrEqualsZero(bd)) {
					return false;
				}
			}
			return true;
		}
	}

	/**
	 * 方法名: isAllNonPositive <br/>
	 * 描述: 均是非正数 <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/3/17 1:45 下午
	 */
	public static boolean isAllNonpositive(BigDecimal... bds) {
		if (ArrayUtils.isEmpty(bds)) {
			return true;
		} else {
			for (BigDecimal bd : bds) {
				if (greaterThanZero(bd)) {
					return false;
				}
			}
			return true;
		}
	}

	/**
	 * 方法名: isAllNonnegative <br/>
	 * 描述: 均是非负数 <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/3/17 1:41 下午
	 */
	public static boolean isAllNonnegative(BigDecimal... bds) {
		if (ArrayUtils.isEmpty(bds)) {
			return true;
		} else {
			for (BigDecimal bd : bds) {
				if (lessThanZero(bd)) {
					return false;
				}
			}
			return true;
		}
	}

	/**
	 * 方法名: isAllNegative <br/>
	 * 描述: 均是负数 <br/>
	 * 作者: LGF <br/>
	 * 日期: Created in 2023/3/17 12:44 下午
	 */
	public static boolean isAllNegative(BigDecimal... bds) {
		if (ArrayUtils.isEmpty(bds)) {
			return true;
		} else {
			for (BigDecimal bd : bds) {
				if (greaterThanEqualsZero(bd)) {
					return false;
				}
			}
			return true;
		}
	}

	/**
	 * @Method max <br/>
	 * @Description 取最大值(null值默认为0) <br/>
	 * @Param values <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2023/6/13 19:05 <br/>
	 * @Return java.math.BigDecimal
	 */
	public static BigDecimal max(BigDecimal... values) {
		if (ArrayUtils.isEmpty(values)) {
			return ZERO;
		}
		BigDecimal[] arr = ArrayUtils.toArray(values);
		// 如果全是负数, 初始值不能为0
		BigDecimal max = isAllNegative(values) ? arr[0] : ZERO;
		for (BigDecimal e : values) {
			e = isEmpty(e) ? ZERO : e;
			// 取最大值
			max = e.max(max);
		}
		return max;
	}

	/**
	 * @Method min <br/>
	 * @Description 取最小值(null值默认为0) <br/>
	 * @Param values <br/>
	 * @Author Cao.Yu <br/>
	 * @Date 2023/6/13 19:05 <br/>
	 * @Return java.math.BigDecimal
	 */
	public static BigDecimal min(BigDecimal... values) {
		if (ArrayUtils.isEmpty(values)) {
			return ZERO;
		}
		BigDecimal min = ZERO;
		for (BigDecimal e : values) {
			e = isEmpty(e) ? ZERO : e;
			// 取最小值
			min = e.min(min);
		}
		return min;
	}

}
